package main

import (
	"fmt"
	"log"
	"time"

	"gorm.io/driver/mysql" // 还需要 github.com/go-sql-driver/mysqkl? 需要，增强封装
	"gorm.io/gorm"
)

var db *gorm.DB // 重新封装了，为了增强功能, 后面操作都需要 db

func init() {
	var err error
	dsn := "root:123456@tcp(127.0.0.1:3306)/test?parseTime=true&loc=Local"
	mysqlDialector := mysql.Open(dsn)
	db, err = gorm.Open(mysqlDialector, &gorm.Config{
		// gorm.Open -> dialector.Initialize() -> sql.Open("mysql",dsn)
		// 导入了驱动包，驱动包的 init()执行了，注册了 mysql 这个名字和对应的驱动对象
		// 全局选项
		// Logger: logger.Default.LogMode(logger.Info),
	})
	if err != nil {
		log.Fatal(err, "!!!")
	}
	db = db.Debug()
	fmt.Println(db)
}

type Emp struct {
	// EmpNo int // 默认对应emp_no
	EmpNo int `gorm:"primaryKey"`
	// FirstName string // 默认对应first_name
	Fn string `gorm:"column:first_name"`
}

// GORM 提供了一组约定。表名约定，结构体的
func (Emp) TableName() string {
	return "employees"
}

type Student struct { // students
	Id       int        `gorm:"primaryKey"`
	Name     string     `gorm:"type:varchar(48);not null"` // text, longtext, varchar char
	Age      int        `gorm:"type:tinyint"`              // tinyint, shortint, bigint
	Birthday *time.Time // *time.Time
	Gender   int        `gorm:"size:8"` // uint8
}

func (s *Student) String() string {
	return fmt.Sprintf("<Stu id:%d, %s, %d>", s.Id, s.Name, s.Age)
}

func main() {
	// var instance Emp
	// result := db.Take(&instance) // 拿一条回来
	// fmt.Println(result.Error, result.Error == nil)
	// fmt.Println(instance)

	// 创建表
	// db.Migrator().DropTable(&Student{})
	// db.Migrator().CreateTable(&Student{})

	// 插入数据
	// t1 := time.Now()
	// t2, _ := time.Parse("2006/01/02", "1993/05/04")
	// // s1 := Student{Name: "Yz", Birthday: &t1} // ID可以给，可以不给
	// // fmt.Println(s1, "#####")                 // 临时的，非持久的

	// s2 := Student{Id: 100, Name: "jerry", Birthday: &t1}
	// s3 := Student{Name: "ben", Birthday: &t2}
	// fmt.Println(s2, s3, "^^^")

	// // r := db.Create(&s1) // 落地了，ACID D 持久化

	// r := db.Create([]*Student{&s2, &s3})
	// if r.Error != nil {
	// 	log.Fatal(r.Error)
	// }
	// // fmt.Println(s1, "%%%%%") // 持久的 存下来了
	// fmt.Println(s2, s3, "%%%%%") // 持久的 存下来了

	// 查询数据 Queryrow limit 1

	// var s Student
	// // db.Take(&s)
	// db.First(&s)
	// // db.Last(&s)
	// fmt.Println(s)
	// s = Student{}
	// // db.Take(&s, 101) // (&Student{Id:1}, 103)
	// if db.Error != nil {
	// 	log.Fatal(db.Error)
	// }
	// fmt.Println(s)

	// 查询多行 Query rows Find
	// var students []*Student
	// db.Distinct("id", "name").Find(&students)
	// db.Select("id").Find(&students)
	// db.Select([]string{"id", "name"}).Find(&students)
	// db.Select("id, name").Limit(2).Offset(3).Find(&students)
	// db.Find(&students, 1, 101, 200)
	// where
	// db.
	// Where(
	// Not(
	// 推荐 字符串条件
	// "id > 100",
	// 103,
	// "name = ?", "tom",
	// "id = ? and name = ?", 1, "YZ",
	// &Student{Id: 100},
	// &Student{Id: 1, Name: "tom"},                  // id 0, name "" 示例中零值会忽略
	// map[string]interface{}{"id": 1, "name": "Yz"}, // 不会忽略空值
	// ).
	// Or("id = 101").

	// Order("name").Order("id desc").
	// Order("name desc, id desc").
	// Find(&students)

	// 分组
	// type Result struct {
	// 	Name string
	// 	C    int
	// }
	// // 简单版本 分组
	// var rows []*Result
	// db.Select("name", "count(id) as c").Group("name").
	// 	// Table("students").// 表名字符串
	// 	Model(&Student{}).
	// 	// Find(&rows)
	// 	Scan(&rows)
	// if db.Error != nil {
	// 	log.Fatal(db.Error, "######")
	// }
	// fmt.Println(rows)
	// for _, v := range rows {
	// 	fmt.Println(v)
	// }

	// var students []*Result
	// 繁琐版本 分组
	// rows, err := db.
	// 	Table("students").
	// 	Select("name", "count(id) as c").
	// 	Group("name"). // 非分组字段显示没有意义
	// 	// join
	// 	// Find(&students)
	// 	Rows()
	// if db.Error != nil {
	// 	log.Fatal(err)
	// }
	// for rows.Next() {
	// 	var r Result
	// 	err = rows.Scan(&r.name, &r.c)
	// 	if err != nil {
	// 		fmt.Println(err, "$$$$$")
	// 		continue
	// 	}
	// 	fmt.Println(r)
	// }

}
